package com.u1zz.zeus.module.iot.service.productcategory;

import com.u1zz.zeus.framework.common.util.object.BeanUtils;
import com.u1zz.zeus.module.iot.common.RedisKeyConstants;
import com.u1zz.zeus.module.iot.controller.admin.productcategory.vo.ProductCategoryListReqVO;
import com.u1zz.zeus.module.iot.controller.admin.productcategory.vo.ProductCategorySaveReqVO;
import com.u1zz.zeus.module.iot.dal.dataobject.productcategory.ProductCategoryDO;
import com.u1zz.zeus.module.iot.dal.mysql.productcategory.ProductCategoryMapper;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

import static com.u1zz.zeus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.u1zz.zeus.module.iot.enums.ErrorCodeConstants.*;

/**
 * 产品分类 Service
 *
 * @author u1zz
 */
@Service
@Validated
public class ProductCategoryService {

    @Resource
    private ProductCategoryMapper productCategoryMapper;

    @CacheEvict(cacheNames = RedisKeyConstants.IOT_CATEGORY, key = "#reqVo.id")
    public Long createProductCategory(ProductCategorySaveReqVO reqVo) {
        // 校验父ID的有效性
        validateParentProductCategory(null, reqVo.getParentId());
        // 校验分类名称的唯一性
        validateProductCategoryCategoryNameUnique(null, reqVo.getParentId(), reqVo.getCategoryName());

        // 插入
        ProductCategoryDO productCategory = BeanUtils.toBean(reqVo, ProductCategoryDO.class);
        productCategoryMapper.insert(productCategory);
        // 返回
        return productCategory.getId();
    }

    @CacheEvict(cacheNames = RedisKeyConstants.IOT_CATEGORY, key = "#reqVo.id")
    public void updateProductCategory(ProductCategorySaveReqVO reqVo) {
        // 校验存在
        validateProductCategoryExists(reqVo.getId());
        // 校验父ID的有效性
        validateParentProductCategory(reqVo.getId(), reqVo.getParentId());
        // 校验分类名称的唯一性
        validateProductCategoryCategoryNameUnique(reqVo.getId(), reqVo.getParentId(), reqVo.getCategoryName());

        // 更新
        ProductCategoryDO updateObj = BeanUtils.toBean(reqVo, ProductCategoryDO.class);
        productCategoryMapper.updateById(updateObj);
    }

    public void deleteProductCategory(Long id) {
        // 校验存在
        validateProductCategoryExists(id);
        // 校验是否有子产品分类
        if (productCategoryMapper.selectCountByParentId(id) > 0) {
            throw exception(PRODUCT_CATEGORY_EXITS_CHILDREN);
        }
        // 删除
        productCategoryMapper.deleteById(id);
    }

    private void validateProductCategoryExists(Long id) {
        if (productCategoryMapper.selectById(id) == null) {
            throw exception(PRODUCT_CATEGORY_NOT_EXISTS);
        }
    }

    private void validateParentProductCategory(Long id, Long parentId) {
        if (parentId == null || ProductCategoryDO.PARENT_ID_ROOT.equals(parentId)) {
            return;
        }
        // 1. 不能设置自己为父产品分类
        if (Objects.equals(id, parentId)) {
            throw exception(PRODUCT_CATEGORY_PARENT_ERROR);
        }
        // 2. 父产品分类不存在
        ProductCategoryDO parentProductCategory = productCategoryMapper.selectById(parentId);
        if (parentProductCategory == null) {
            throw exception(PRODUCT_CATEGORY_PARENT_NOT_EXITS);
        }
        // 3. 递归校验父产品分类，如果父产品分类是自己的子产品分类，则报错，避免形成环路
        if (id == null) { // id 为空，说明新增，不需要考虑环路
            return;
        }
        for (int i = 0; i < Short.MAX_VALUE; i++) {
            // 3.1 校验环路
            parentId = parentProductCategory.getParentId();
            if (Objects.equals(id, parentId)) {
                throw exception(PRODUCT_CATEGORY_PARENT_IS_CHILD);
            }
            // 3.2 继续递归下一级父产品分类
            if (parentId == null || ProductCategoryDO.PARENT_ID_ROOT.equals(parentId)) {
                break;
            }
            parentProductCategory = productCategoryMapper.selectById(parentId);
            if (parentProductCategory == null) {
                break;
            }
        }
    }

    private void validateProductCategoryCategoryNameUnique(Long id, Long parentId, String categoryName) {
        ProductCategoryDO productCategory = productCategoryMapper.selectByParentIdAndCategoryName(parentId, categoryName);
        if (productCategory == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的产品分类
        if (id == null) {
            throw exception(PRODUCT_CATEGORY_CATEGORY_NAME_DUPLICATE);
        }
        if (!Objects.equals(productCategory.getId(), id)) {
            throw exception(PRODUCT_CATEGORY_CATEGORY_NAME_DUPLICATE);
        }
    }

    @Cacheable(cacheNames = RedisKeyConstants.IOT_CATEGORY, key = "#id")
    public ProductCategoryDO getProductCategory(Long id) {
        return productCategoryMapper.selectById(id);
    }


    public List<ProductCategoryDO> getProductCategoryList(ProductCategoryListReqVO reqVO) {
        return productCategoryMapper.selectList(reqVO);
    }


}